library ieee;
use ieee.std_logic_1164.all;
use IEEE.NUMERIC_STD.all;

entity SuperArbiter is
  port
    (
      -- clk, active-low reset
      clk, nReset  : in  std_logic;
      -- memory signals (in order)
      memAddr      : out std_logic_vector(15 downto 0);  -- mem address being read/written
      memWriteData : out std_logic_vector(31 downto 0);  -- mem data to be written
      memWEN       : out std_logic;     -- write enable
      memREN       : out std_logic;     -- read enable
      memReadData  : in  std_logic_vector(31 downto 0);  -- mem data to be read
      memState     : in  std_logic_vector(1 downto 0);   -- state of mem
      -- Core 1 Arbiter signals (in order)
      a1Addr       : in  std_logic_vector(15 downto 0);  -- mem address being read/written
      a1WriteData  : in  std_logic_vector(31 downto 0);  -- mem data to be written
      a1WEN        : in  std_logic;     -- write enable
      a1REN        : in  std_logic;     -- read enable
      a1ReadData   : out std_logic_vector(31 downto 0);  -- mem data to be read
      a1State      : out std_logic_vector(1 downto 0);   -- state of mem
      -- Core 2 Arbiter signals (in order)
      a2Addr       : in  std_logic_vector(15 downto 0);  -- mem address being read/written
      a2WriteData  : in  std_logic_vector(31 downto 0);  -- mem data to be written
      a2WEN        : in  std_logic;     -- write enable
      a2REN        : in  std_logic;     -- read enable
      a2ReadData   : out std_logic_vector(31 downto 0);  -- mem data to be read
      a2State      : out std_logic_vector(1 downto 0)    -- state of mem
      );
end SuperArbiter;

architecture SuperArbiter_arch of SuperArbiter is

  type   arbiter_service_state_type is (Svc_A1, Svc_A2);
  signal state, nextstate : arbiter_service_state_type;
  
begin
  
  state_transition : process(clk, nReset)
  begin
    if (nReset = '0') then
      state <= Svc_A1;
    elsif (rising_edge(clk)) then
      state <= nextstate;
    end if;
  end process;

  nextstate_logic : process(clk, nReset, state, memReadData, memState, a1Addr, a2Addr, a1WriteData, a2WriteData, a1WEN, a2WEN, a1REN, a2REN)
  begin
    nextstate <= state;

    case state is
      
      when Svc_A1 =>
        if (a1WEN = '0' and a1REN = '0') then
          if (a2WEN = '1' or a2REN = '1') then
            nextstate <= Svc_A2;
          end if;
        else
          if(memState = "10") then
            nextstate <= Svc_A2;
          end if;
        end if;
        
      when Svc_A2 =>
        if (a2WEN = '0' and a2REN = '0') then
          if (a1WEN = '1' or a1REN = '1') then
            nextstate <= Svc_A1;
          end if;
        else
          if (memState = "10") then
            nextstate <= Svc_A1;
          end if;
        end if;
        
      when others =>
        nextstate <= state;
        
    end case;
    
  end process;

  output_logic : process(clk, nReset, state, memReadData, memState, a1Addr, a2Addr, a1WriteData, a2WriteData, a1WEN, a2WEN, a1REN, a2REN)
  begin
    memAddr      <= x"0000";
    memWriteData <= x"00000000";
    memWEN       <= '0';
    memREN       <= '0';
    a2State      <= "01";
    a1State      <= "01";
    a1ReadData   <= x"BAD1BAD1";
    a2ReadData   <= x"BAD1BAD1";

    case state is
      
      when Svc_A1 =>
        memAddr      <= a1Addr;
        memWriteData <= a1WriteData;
        memWEN       <= a1WEN;
        memREN       <= a1REN;
        a1ReadData   <= memReadData;
        a1State      <= memState;
        a2State      <= "01";
        a2ReadData   <= x"BAD1BAD1";
        if(a1WEN = '0' and a1REN = '0') then
          if(a2WEN = '1' or a2REN = '1') then
            memAddr      <= a2Addr;
            memWriteData <= a2WriteData;
            memWEN       <= a2WEN;
            memREN       <= a2REN;
            a2ReadData   <= memReadData;
            a2State      <= memState;
          end if;
        end if;
        
      when Svc_A2 =>
        memAddr      <= a2Addr;
        memWriteData <= a2WriteData;
        memWEN       <= a2WEN;
        memREN       <= a2REN;
        a2ReadData   <= memReadData;
        a2State      <= memState;
        a1State      <= "01";
        a1ReadData   <= x"BAD1BAD1";
        if(a2WEN = '0' and a2REN = '0') then
          if(a1WEN = '1' or a2WEN = '1') then
            memAddr      <= a1Addr;
            memWriteData <= a1WriteData;
            memWEN       <= a1WEN;
            memREN       <= a1REN;
            a1ReadData   <= memReadData;
            a1State      <= memState;
          end if;
        end if;
        
      when others =>
                                        -- service a1 by default
        memAddr      <= a1Addr;
        memWriteData <= a1WriteData;
        memWEN       <= a1WEN;
        memREN       <= a1REN;
        a1ReadData   <= memReadData;
        a1State      <= memState;
        a2State      <= "01";
        
    end case;
    
  end process;
  
end SuperArbiter_arch;
